﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Services;
using System.Web.SessionState;

using PickGold.Arguments;
using PickGold.Base.Proxies;

using HsjCommon = PickGold.Common;

namespace PickGold.Base.Remoting
{
	/// <summary>
	/// 远程代理包装。
	/// </summary>
	/// <typeparam name="API">远程对象类型。</typeparam>
	class MethodInvokerRemoteProxy<API> : MethodInvokerRemoteRealProxy where API : class
	{
		public static Dictionary<string, string> DuplexNames;

		#region ctor

		/// <summary>
		/// 使用应用程序配置文件中的默认目标终结点初始化 System.ServiceModel.ClientBase&lt;TChannel&gt; 类的新实例。
		/// </summary>
		/// <exception cref="System.InvalidOperationException">配置文件中没有默认的终结点信息，或者文件中有多个终结点，或者没有配置文件。</exception>
		public MethodInvokerRemoteProxy()
			: base(typeof(API))
		{
			this.InnerProxy = new MethodInvokerWcfClient();
		}
		/// <summary>
		/// 通过使用 client 作为客户端应用程序用以连接服务的对象来初始化 System.ServiceModel.ClientBase&lt;TChannel&gt; 类的新实例。
		/// </summary>
		/// <param name="client">客户端应用程序用以连接服务的对象。</param>
		/// <exception cref="System.ArgumentNullException">客户端应用程序用以连接服务的对象实例为 Null。</exception>
		public MethodInvokerRemoteProxy(IMethodInvokerClient client)
			: base(typeof(API))
		{
			if (client == null)
				throw new ArgumentNullException();

			this.InnerProxy = client;
		}
		/// <summary>
		/// 通过使用 callbackInstance 作为双工对话中的回调对象来初始化 System.ServiceModel.ClientBase&lt;TChannel&gt; 类的新实例。
		/// </summary>
		/// <param name="callbackInstance">客户端应用程序用以侦听来自所连接服务的消息的回调对象。</param>
		/// <exception cref="System.ArgumentNullException">回调实例为 Null。</exception>
		/// <exception cref="System.InvalidOperationException">配置文件中没有默认的终结点信息，或者文件中有多个终结点，或者没有配置文件。</exception>
		public MethodInvokerRemoteProxy(InstanceContext callbackInstance)
			: base(typeof(API))
		{
			this.InnerProxy = new MethodInvokerWcfClient(callbackInstance);
		}
		/// <summary>
		/// 使用应用程序配置文件中由 endpointConfigurationName 指定的配置信息来初始化 System.ServiceModel.ClientBase&lt;TChannel&gt; 类的新实例。
		/// </summary>
		/// <param name="endpointConfigurationName">应用程序配置文件中的终结点的名称。</param>
		/// <exception cref="System.ArgumentNullException">指定的终结点信息为 Null。</exception>
		/// <exception cref="System.InvalidOperationException">无法找到终结点或者终结点协定无效。</exception>
		public MethodInvokerRemoteProxy(string endpointConfigurationName)
			: base(typeof(API))
		{
			if (string.IsNullOrEmpty(IsDuplex(endpointConfigurationName)))
				this.InnerProxy = new MethodInvokerWcfClient(endpointConfigurationName);
			else
				this.InnerProxy = new MethodInvokerDuplexWcfClient(endpointConfigurationName);
		}
		/// <summary>
		/// 使用指定的绑定和目标地址初始化 System.ServiceModel.ClientBase&lt;TChannel&gt; 类的新实例。
		/// </summary>
		/// <param name="binding">用于调用服务的绑定。</param>
		/// <param name="remoteAddress">服务终结点的地址。</param>
		/// <exception cref="System.ArgumentNullException">绑定为 Null。</exception>
		/// <exception cref="System.ArgumentNullException">远程地址为 Null。</exception>
		public MethodInvokerRemoteProxy(Binding binding, EndpointAddress remoteAddress)
			: base(typeof(API))
		{
			this.InnerProxy = new MethodInvokerWcfClient(binding, remoteAddress);
		}
		/// <summary>
		/// 使用指定的回调服务和终结点配置信息初始化 System.ServiceModel.ClientBase&lt;TChannel&gt; 类的新实例。
		/// </summary>
		/// <param name="callbackInstance">客户端用以侦听来自所连接服务的消息的回调对象。</param>
		/// <param name="endpointConfigurationName">应用程序配置文件中的终结点的名称。</param>
		/// <exception cref="System.ArgumentNullException">回调实例为 Null。</exception>
		/// <exception cref="System.ArgumentNullException">终结点为 Null。</exception>
		/// <exception cref="System.InvalidOperationException">无法找到终结点或者终结点协定无效。</exception>
		public MethodInvokerRemoteProxy(InstanceContext callbackInstance, string endpointConfigurationName)
			: base(typeof(API))
		{
			if (string.IsNullOrEmpty(IsDuplex(endpointConfigurationName)))
				this.InnerProxy = new MethodInvokerWcfClient(callbackInstance, endpointConfigurationName);
			else
				this.InnerProxy = new MethodInvokerDuplexWcfClient(callbackInstance, endpointConfigurationName);
		}
		/// <summary>
		/// 使用指定的目标地址和终结点信息初始化 System.ServiceModel.ClientBase&lt;TChannel&gt; 类的新实例。
		/// </summary>
		/// <param name="endpointConfigurationName">应用程序配置文件中的终结点的名称。</param>
		/// <param name="remoteAddress">服务的地址。</param>
		/// <exception cref="System.ArgumentNullException">终结点为 Null。</exception>
		/// <exception cref="System.ArgumentNullException">远程地址为 Null。</exception>
		/// <exception cref="System.InvalidOperationException">无法找到终结点或者终结点协定无效。</exception>
		public MethodInvokerRemoteProxy(string endpointConfigurationName, EndpointAddress remoteAddress)
			: base(typeof(API))
		{
			if (string.IsNullOrEmpty(IsDuplex(endpointConfigurationName)))
				this.InnerProxy = new MethodInvokerWcfClient(endpointConfigurationName, remoteAddress);
			else
				this.InnerProxy = new MethodInvokerDuplexWcfClient(endpointConfigurationName, remoteAddress);
		}
		/// <summary>
		/// 初始化 System.ServiceModel.ClientBase&lt;TChannel&gt; 类的新实例。
		/// </summary>
		/// <param name="endpointConfigurationName">应用程序配置文件中的终结点的名称。</param>
		/// <param name="remoteAddress">服务的地址。</param>
		/// <exception cref="System.ArgumentNullException">终结点为 Null。</exception>
		/// <exception cref="System.ArgumentNullException">远程地址为 Null。</exception>
		/// <exception cref="System.InvalidOperationException">无法找到终结点或者终结点协定无效。</exception>
		public MethodInvokerRemoteProxy(string endpointConfigurationName, string remoteAddress)
			: base(typeof(API))
		{
			if (string.IsNullOrEmpty(IsDuplex(endpointConfigurationName)))
				this.InnerProxy = new MethodInvokerWcfClient(endpointConfigurationName, remoteAddress);
			else
				this.InnerProxy = new MethodInvokerDuplexWcfClient(endpointConfigurationName, remoteAddress);
		}
		/// <summary>
		/// 初始化 System.ServiceModel.ClientBase&lt;TChannel&gt; 类的新实例。
		/// </summary>
		/// <param name="callbackInstance">回调服务。</param>
		/// <param name="binding">用于调用服务的绑定。</param>
		/// <param name="remoteAddress">服务终结点的地址。</param>
		/// <exception cref="System.ArgumentNullException">回调实例为 Null。</exception>
		/// <exception cref="System.ArgumentNullException">绑定为 Null。</exception>
		/// <exception cref="System.ArgumentNullException">远程地址为 Null。</exception>
		public MethodInvokerRemoteProxy(InstanceContext callbackInstance, Binding binding, EndpointAddress remoteAddress)
			: base(typeof(API))
		{
			this.InnerProxy = new MethodInvokerWcfClient(callbackInstance, binding, remoteAddress);
		}
		/// <summary>
		/// 初始化 System.ServiceModel.ClientBase&lt;TChannel&gt; 类的新实例。
		/// </summary>
		/// <param name="callbackInstance">客户端用以侦听来自所连接服务的消息的回调对象。</param>
		/// <param name="endpointConfigurationName">应用程序配置文件中的终结点的名称。</param>
		/// <param name="remoteAddress">服务的地址。</param>
		/// <exception cref="System.ArgumentNullException">回调实例为 Null。</exception>
		/// <exception cref="System.ArgumentNullException">终结点为 Null。</exception>
		/// <exception cref="System.ArgumentNullException">远程地址为 Null。</exception>
		/// <exception cref="System.InvalidOperationException">无法找到终结点或者终结点协定无效。</exception>
		public MethodInvokerRemoteProxy(InstanceContext callbackInstance, string endpointConfigurationName, EndpointAddress remoteAddress)
			: base(typeof(API))
		{
			if (string.IsNullOrEmpty(IsDuplex(endpointConfigurationName)))
				this.InnerProxy = new MethodInvokerWcfClient(callbackInstance, endpointConfigurationName, remoteAddress);
			else
				this.InnerProxy = new MethodInvokerDuplexWcfClient(callbackInstance, endpointConfigurationName, remoteAddress);
		}
		/// <summary>
		/// 初始化 System.ServiceModel.ClientBase&lt;TChannel&gt; 类的新实例。
		/// </summary>
		/// <param name="callbackInstance">客户端用以侦听来自所连接服务的消息的回调对象。</param>
		/// <param name="endpointConfigurationName">应用程序配置文件中的终结点的名称。</param>
		/// <param name="remoteAddress">服务的地址。</param>
		/// <exception cref="System.ArgumentNullException">回调实例为 Null。</exception>
		/// <exception cref="System.ArgumentNullException">终结点为 Null。</exception>
		/// <exception cref="System.ArgumentNullException">远程地址为 Null。</exception>
		/// <exception cref="System.InvalidOperationException">无法找到终结点或者终结点协定无效。</exception>
		public MethodInvokerRemoteProxy(InstanceContext callbackInstance, string endpointConfigurationName, string remoteAddress)
			: base(typeof(API))
		{
			if (string.IsNullOrEmpty(IsDuplex(endpointConfigurationName)))
				this.InnerProxy = new MethodInvokerWcfClient(callbackInstance, endpointConfigurationName, remoteAddress);
			else
				this.InnerProxy = new MethodInvokerDuplexWcfClient(callbackInstance, endpointConfigurationName, remoteAddress);
		}

		#endregion

		public static string IsDuplex(string endpointConfigurationName)
		{
			if (DuplexNames == null)
				DuplexNames = new Dictionary<string, string>();
			else if (DuplexNames.ContainsKey(endpointConfigurationName))
				return DuplexNames[endpointConfigurationName];

			var c = GetClientSection();
			if (c == null || c.Endpoints == null || c.Endpoints.Count == 0)
			{
				DuplexNames[endpointConfigurationName] = null;
				return null;
			}

			var t = typeof(IMethodInvokerDuplex).FullName;
			for (var i = 0; i < c.Endpoints.Count; i++)
			{
				if (c.Endpoints[i].Name == endpointConfigurationName)
				{

					if (c.Endpoints[i].Contract == t)
					{
						DuplexNames[endpointConfigurationName] = t;
						return t;
					}

					DuplexNames[endpointConfigurationName] = string.Empty;
					return string.Empty;
				}
			}

			DuplexNames[endpointConfigurationName] = null;
			return null;
		}

		#region Section

		/// <summary>  
		/// 返回Bindings设置  
		/// </summary>  
		/// <returns></returns>  
		public static BindingsSection GetBindingsSection()
		{
			return ConfigurationManager.GetSection("system.serviceModel/bindings") as BindingsSection;
		}
		/// <summary>  
		/// 返回ServicesSection设置  
		/// </summary>  
		/// <returns></returns>  
		public static ServicesSection GetServicesSection()
		{
			return ConfigurationManager.GetSection("system.serviceModel/services") as ServicesSection;
		}
		/// <summary>  
		/// 返回BehaviorsSection设置  
		/// </summary>  
		/// <returns></returns>  
		public static BehaviorsSection GetBehaviorsSection()
		{
			return ConfigurationManager.GetSection("system.serviceModel/behaviors") as BehaviorsSection;
		}
		/// <summary>  
		/// 返回ClientSection设置  
		/// </summary>  
		/// <returns></returns>  
		public static ClientSection GetClientSection()
		{
			return ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;
		}
		#endregion

		#region Binding
		/// <summary>  
		/// 返回BasicHttpBinding设置  
		/// </summary>  
		/// <returns></returns>  
		public static BasicHttpBindingElement GetBasicHttpBindingElement(string name, bool returnDefault)
		{
			var list = GetBindingsSection().BasicHttpBinding.Bindings.Cast<BasicHttpBindingElement>();
			var re = list.FirstOrDefault(w => w.Name == name);
			if (re == null && returnDefault) re = list.FirstOrDefault();
			return re;
		}
		/// <summary>  
		/// 返回NetTcpBindingElement设置  
		/// </summary>  
		/// <returns></returns>  
		public static NetTcpBindingElement GetNetTcpBindingElement(string name, bool returnDefault)
		{
			var list = GetBindingsSection().NetTcpBinding.Bindings.Cast<NetTcpBindingElement>();
			var re = list.FirstOrDefault(w => w.Name == name);
			if (re == null && returnDefault) re = list.FirstOrDefault();
			return re;
		}
		/// <summary>  
		/// 返回WSHttpBindingElement设置  
		/// </summary>  
		/// <returns></returns>  
		public static WSHttpBindingElement GetWSHttpBindingElement(string name, bool returnDefault)
		{
			var list = GetBindingsSection().WSHttpBinding.Bindings.Cast<WSHttpBindingElement>();
			var re = list.FirstOrDefault(w => w.Name == name);
			if (re == null && returnDefault) re = list.FirstOrDefault();
			return re;
		}
		#endregion

		#region Behaviors

		/// <summary>  
		/// 返回ServiceBehaviorElement设置  
		/// </summary>  
		/// <returns></returns>  
		public static ServiceBehaviorElement GetServiceBehaviorElement(string name, bool returnDefault)
		{
			var list = GetBehaviorsSection().ServiceBehaviors.Cast<ServiceBehaviorElement>();
			var re = list.FirstOrDefault(w => w.Name == name);
			if (re == null && returnDefault) re = list.FirstOrDefault();
			return re;
		}
		#endregion

		/// <summary>  
		/// 返回设置是的ChannelEndpointElement  
		/// </summary>  
		/// <param name="name"></param>  
		/// <param name="returnDefault"></param>  
		/// <returns></returns>  
		public static ChannelEndpointElement GetChannelEndpointElement(string name, bool returnDefault)
		{
			var list = GetClientSection().Endpoints.Cast<ChannelEndpointElement>();

			var re = list.FirstOrDefault(w => w.Name == name);
			if (re == null && returnDefault) re = list.FirstOrDefault();
			return re;
		}

		public override IMessage Invoke(IMessage msg)
		{
			//this.Running++;
			this.Message = msg as IMethodMessage;
			msg = MethodInvokerRemoteRealProxy.RemoteInvoke<API>(this.InnerProxy, this.Items, msg, this.EventList[InvokingKey] as InvokeMessageEventHandler);
			this.Message = msg as IMethodMessage;
			//this.Running--;
			return msg;
		}
	}

	class MethodInvokerRemoteCallbackProxy<API> : MethodInvokerProxy where API : class
	{
		protected IMethodInvoker InnerProxy;//IMethodInvoker

		public MethodInvokerRemoteCallbackProxy()
			: base(typeof(API))
		{
			this.InnerProxy = OperationContext.Current.GetCallbackChannel<IMethodInvoker>();
		}

		public MethodInvokerRemoteCallbackProxy(IMethodInvoker proxy)
			: base(typeof(API))
		{
			this.InnerProxy = proxy;
		}

		public override IMessage Invoke(IMessage msg)
		{
			//this.Running++;
			this.Message = msg as IMethodMessage;
			msg = MethodInvokerRemoteRealProxy.RemoteInvoke<API>(this.InnerProxy, this.Items, msg, this.EventList[InvokingKey] as InvokeMessageEventHandler);
			this.Message = msg as IMethodMessage;
			//this.Running--;
			return msg;
		}
	}

	/// <summary>
	/// 之所以分开是为了取真实代理方便。
	/// </summary>
	abstract class MethodInvokerRemoteRealProxy : MethodInvokerProxy
	{
		protected IMethodInvokerClient InnerProxy;//IMethodInvoker//MethodInvokerWcfClient

		protected MethodInvokerRemoteRealProxy() : base() { }
		protected MethodInvokerRemoteRealProxy(Type classToProxy) : base(classToProxy) { }
		protected MethodInvokerRemoteRealProxy(Type classToProxy, IntPtr stub, object stubData) : base(classToProxy, stub, stubData) { }

		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);
			if (this.InnerProxy == null)
				return;

			try
			{
				this.InnerProxy.Close();
			}
			catch (Exception x)
			{
				HsjCommon.LastError = x;
			}
			this.InnerProxy = null;
		}

		/// <summary>
		/// 取WCF客户端对象。
		/// </summary>
		/// <param name="proxy"></param>
		/// <returns></returns>
		public static IMethodInvokerClient GetClient(object proxy)
		{
			proxy = RemotingServices.GetRealProxy(proxy);
			if (proxy == null)
				return null;

			var real = proxy as MethodInvokerRemoteRealProxy;
			if (real == null)
				return null;

			return real.InnerProxy;
		}
	}
}
